  // CheckersBoard Engine API - Native Code Layer
 // CB Threading CPP module
////////////////////////////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Threading.h"

// Function for creating events
void InitEvents(CBSynch *pS)
{
	for(int i = 0; i < CB_EVENT_COUNT; i++)
		pS->hEvents[i] = ::CreateEvent(NULL, TRUE, FALSE, NULL);
}

// Function for closing events
void CloseEvents(CBSynch *pS)
{
	for(int i = 0; i < CB_EVENT_COUNT; i++)
		::CloseHandle(pS->hEvents[i]);
}


// Thread for computing move of CheckersBoard engines
DWORD WINAPI CBEngineThread(LPVOID lpThreadParameter)
{
	// init shared data
	CBThreadParams* pParams = (CBThreadParams*)lpThreadParameter;
	CBSynch* pSynch = pParams->pSynch;
	CB_APIStruct* pAPI = pParams->pAPI;

	// set the highest priority
	::SetThreadPriority(::GetCurrentThread(), THREAD_PRIORITY_HIGHEST);

	while(true)
	{
		// wait for work
		DWORD dwResult = ::WaitForMultipleObjects(CB_ENGINE_EVENT_COUNT, pSynch->hEvents + CB_ENGINE_INDEX, FALSE, INFINITE);

		// if event signalled
		if(dwResult >= WAIT_OBJECT_0 && dwResult < WAIT_OBJECT_0 + CB_EVENT_COUNT)
		{
			dwResult -= WAIT_OBJECT_0;
			dwResult += CB_ENGINE_INDEX;

			switch(dwResult)
			{
			case CB_EVENT_COMPUTEMOVE:
				// signalled event to compute the move
				{
					::ResetEvent(pSynch->hEvents[CB_EVENT_COMPUTEMOVE]);

					// check, if engine is not busy - sign of error
					if(getenginebusy(pAPI) == 0) 
					{
						// set engine busy
						setenginebusy(pAPI, 1);

						// compute the move
						getMove(pAPI, pParams->pBoard, pParams->color, pParams->maxtime, pParams->move);

						// set engine is not busy
						setenginebusy(pAPI, 0);
					}

					// check, if engine has not been aborted
					// raise move-computed event only in case of not aborting CB engine
					if(pAPI->abortEngine == 0) 
					{
						::SetEvent(*pParams->phMoveComputed);
					}
					else
					{
						pAPI->abortEngine = 0;
					}
				} break;
			case CB_EVENT_TERMINATE:
				// signalled event to terminate
				::ResetEvent(pSynch->hEvents[CB_EVENT_TERMINATE]);
				goto Exit;
				break;
			}
		} //if
	} // while

Exit:;
	::SetEvent(pSynch->hEvents[CB_EVENT_THREAD_EXITED]);
	return 0;
}

